/*******************************************************************************
 * Copyright (c) 2003 Boris Pruessmann and others. All rights reserved. This
 * program and the accompanying materials are made available under the terms of
 * the Common Public License v0.5 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.dialogs;

import com.google.common.collect.Sets;

import net.sourceforge.perforce.core.api.BaseFileTypeEnum;
import net.sourceforge.perforce.core.api.FileType;
import net.sourceforge.perforce.core.api.FileTypeModifierEnum;
import net.sourceforge.perforce.core.api.IFileType;
import net.sourceforge.perforce.core.api.ServerStorageMethodEnum;
import net.sourceforge.perforce.ui.internal.Policy;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Shell;

import java.util.Set;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class FileTypeDialog extends Dialog {

  /** Stores the buttons for the base file types. */
  private Button[] baseFileTypeButtons;

  /** Stores the buttons for the file type modifiers. */
  private Button[] fileTypeModifierButtons;

  /** Stores the buttons for the server storage method. */
  private Button[] serverStorageMethodButtons;

  /** Stores the filetype. */
  private IFileType fileType;

  /**
   * Constructor for FileTypeDialog.
   * 
   * @param parentShell the parent shell.
   * @param theFileType the file type.
   */
  public FileTypeDialog(Shell parentShell, IFileType theFileType) {
    super(parentShell);

    Policy.assertNotNull(theFileType);

    fileType = theFileType;
  }

  @Override
  protected void okPressed() {
    buildFileTypeFromSelection();
    super.okPressed();
  }

  /**
   * Returns a file type that matches the selection of the dialog.
   * 
   * @return the file type.
   */
  public IFileType getFileType() {
    return fileType;
  }

  @Override
  protected void configureShell(Shell newShell) {
    super.configureShell(newShell);
    newShell.setText(Policy.bind("FileTypeDialog.Change_File_Type")); //$NON-NLS-1$
  }

  @Override
  protected Control createDialogArea(Composite parent) {
    Policy.assertNotNull(parent);

    Composite composite = DialogUtils.createComposite(parent, 1);

    // Base File Types
    Group baseFileTypeGroup = DialogUtils.createGroup(composite, 6);
    baseFileTypeGroup.setText(Policy.bind("FileTypeDialog.Base_File_Typ")); //$NON-NLS-1$

    contributeBaseFileTypes(baseFileTypeGroup);


    // File Type Modifiers
    Group fileTypeModifiersGroup = DialogUtils.createGroup(composite, 2);
    fileTypeModifiersGroup.setText(Policy.bind("FileTypeDialog.File_Type_Modifiers")); //$NON-NLS-1$

    contributeFileTypeModifiers(fileTypeModifiersGroup);


    // Server Storage Method
    Group serverStorageMethodGroup = DialogUtils.createGroup(composite, 1);
    serverStorageMethodGroup.setText(Policy.bind("FileTypeDialog.Server_Storage_Method")); //$NON-NLS-1$

    contributeServerStorageMethods(serverStorageMethodGroup);


    // change selections according to file type
    loadSelectionFromFileType();

    return composite;
  }

  /** Builds a file type object from the seletion. */
  private void buildFileTypeFromSelection() {
    BaseFileTypeEnum baseFileType = null;
    for (int i = 0; i < baseFileTypeButtons.length; i++) {
      if (baseFileTypeButtons[i].getSelection()) {
        baseFileType = BaseFileTypeEnum.fromId(i);
        break;
      }
    }

    Set<Object> modifierSet = Sets.newHashSet();
    for (int i = 0; i < fileTypeModifierButtons.length; i++) {
      if (fileTypeModifierButtons[i].getSelection()) {
        modifierSet.add(FileTypeModifierEnum.fromId(i));
      }
    }

    for (int i = 0; i < serverStorageMethodButtons.length; i++) {
      if (serverStorageMethodButtons[i].getSelection()) {
        modifierSet.add(ServerStorageMethodEnum.fromId(i));
      }
    }

    fileType = new FileType(baseFileType, modifierSet);
  }

  /** Loads the selection of the buttons from the file type. */
  private void loadSelectionFromFileType() {
    loadSelectionForBaseFileType();
    loadSelectionForModifiers();
  }

  /** Loads the selection for the fileType's modifiers. */
  private void loadSelectionForModifiers() {
    serverStorageMethodButtons[0].setSelection(true);

    Set<?> modifierSet = fileType.getModifierSet();
    for (Object element : modifierSet) {
      if (element instanceof ServerStorageMethodEnum) {
        ServerStorageMethodEnum storageMethod = (ServerStorageMethodEnum) element;
        serverStorageMethodButtons[0].setSelection(false);
        serverStorageMethodButtons[storageMethod.getId()].setSelection(true);
      } else if (element instanceof FileTypeModifierEnum) {
        FileTypeModifierEnum typeModifier = (FileTypeModifierEnum) element;
        fileTypeModifierButtons[typeModifier.getId()].setSelection(true);

      } else {
        throw new IllegalStateException("Unsupported modifier: " + element); //$NON-NLS-1$
      }
    }
  }

  /** Loads the selection for the fileType's base file type. */
  private void loadSelectionForBaseFileType() {
    BaseFileTypeEnum baseFileTypeEnum = fileType.getBaseFileType();
    baseFileTypeButtons[baseFileTypeEnum.getId()].setSelection(true);
  }

  /**
   * Called to add radio buttons for the supported server storage methods.
   * 
   * @param parent the group to which the buttons are added.
   */
  private void contributeServerStorageMethods(Group parent) {
    final String[] serverStorageMethods =
        {Policy.bind("FileTypeDialog.s&erver_stores_using_default_method"), //$NON-NLS-1$
            Policy.bind("FileTypeDialog.server_stores_compressed_file_per_revision"), //$NON-NLS-1$
            Policy.bind("FileTypeDialog.server_stores_deltas_in_RCS_format"), //$NON-NLS-1$
            Policy.bind("FileTypeDialog.server_stores_full_file_per_revision"), //$NON-NLS-1$
            Policy.bind("FileTypeDialog.server_stores_only_single_head_revision") //$NON-NLS-1$
        };

    serverStorageMethodButtons = new Button[serverStorageMethods.length];

    for (int i = 0; i < serverStorageMethods.length; i++) {
      serverStorageMethodButtons[i] = new Button(parent, SWT.RADIO);
      serverStorageMethodButtons[i].setText(serverStorageMethods[i]);
    }
  }

  /**
   * Called to add checkboxes for each supported file type modifiert.
   * 
   * @param parent the group to which the buttons are added.
   */
  private void contributeFileTypeModifiers(Group parent) {
    final String[] fileTypeModifiers = {Policy.bind("FileTypeDialog.exec_bit_set_on_client"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.always_writeable_on_client"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.$keyword_$_expansion"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.only_$Id_$_&&_$Header_$"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.preserve_file_modification_times"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.disallow_multiple_opens_of_this_file") //$NON-NLS-1$
        };

    fileTypeModifierButtons = new Button[fileTypeModifiers.length];

    // 1. Row
    fileTypeModifierButtons[0] = new Button(parent, SWT.CHECK);
    fileTypeModifierButtons[0].setText(fileTypeModifiers[0]);

    DialogUtils.createLabel(parent, ""); //$NON-NLS-1$

    // 2. Row
    fileTypeModifierButtons[1] = new Button(parent, SWT.CHECK);
    fileTypeModifierButtons[1].setText(fileTypeModifiers[1]);

    DialogUtils.createLabel(parent, ""); //$NON-NLS-1$

    // 3. Row
    fileTypeModifierButtons[2] = new Button(parent, SWT.CHECK);
    fileTypeModifierButtons[2].setText(fileTypeModifiers[2]);

    fileTypeModifierButtons[3] = new Button(parent, SWT.CHECK);
    fileTypeModifierButtons[3].setText(fileTypeModifiers[3]);

    // 4. Row
    fileTypeModifierButtons[4] = new Button(parent, SWT.CHECK);
    fileTypeModifierButtons[4].setText(fileTypeModifiers[4]);

    DialogUtils.createLabel(parent, ""); //$NON-NLS-1$

    // 5. Row
    fileTypeModifierButtons[5] = new Button(parent, SWT.CHECK);
    fileTypeModifierButtons[5].setText(fileTypeModifiers[5]);
  }

  /**
   * Called to add a radio button for each supported base file type.
   * 
   * @param parent the group to which the buttons are added.
   */
  private void contributeBaseFileTypes(Group parent) {
    final String[] baseFileTypes = {Policy.bind("FileTypeDialog.Text"), //$NON-NLS-1$ 
        Policy.bind("FileTypeDialog.Binary"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.Symlink"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.Resource"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.Apple"), //$NON-NLS-1$
        Policy.bind("FileTypeDialog.Unicode") //$NON-NLS-1$
        };

    baseFileTypeButtons = new Button[baseFileTypes.length];
    for (int i = 0; i < baseFileTypes.length; i++) {
      baseFileTypeButtons[i] = new Button(parent, SWT.RADIO);
      baseFileTypeButtons[i].setText(baseFileTypes[i]);
    }
  }
}
